package com.ant.storage.service.impl;


import com.ant.storage.common.ResultCode;
import com.ant.storage.common.ResultVo;
import com.ant.storage.dto.InvoiceInfoDto;
import com.ant.storage.handler.AntException;
import com.ant.storage.mapper.CapitalAccountMapper;
import com.ant.storage.mapper.InvoiceInfoMapper;
import com.ant.storage.mapper.UserCityMapper;
import com.ant.storage.pojo.*;
import com.ant.storage.service.*;
import com.ant.storage.utils.RandomUtil;
import com.ant.storage.wechat.WeChatUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.taobao.api.ApiException;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.ServletContext;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author melon
 * @since 2023-11-24
 */
@Service
public class InvoiceInfoServiceImpl extends ServiceImpl<InvoiceInfoMapper, InvoiceInfo> implements IInvoiceInfoService {

    @Autowired
    public ServletContext servletContext;

    @Resource
    private CapitalAccountMapper capitalAccountMapper;

    @Resource
    private IPurchaserRecordImgService imgService;

    @Resource
    private IAuditListService auditListService;

    @Resource
    private IReimburseDetailService detailService;

    @Resource
    private IInvoiceInfoService infoService;

    @Resource
    private IHouseLeaseService leaseService;

    @Resource
    private IUserInfoService userInfoService;

    @Resource
    private IBidInformationService bidInformationService;

    @Autowired
    public IApprovalMsgService approvalMsgService;

    @Autowired
    public ICapitalAccountService accountService;


    @Resource
    private UserCityMapper userCityMapper;


    @Override
    public PageInfo<InvoiceInfo> getInvoiceInfoPage(InvoiceInfoDto dto) {
        try {
            UserInfo userInfo = (UserInfo) servletContext.getAttribute("userInfo");
            List<Integer> cityId = cityBatchIds(userInfo.getId());

            PageHelper.startPage(dto.getPageIndex(), dto.getPageSize());
            QueryWrapper<InvoiceInfo> wrapper = new QueryWrapper<>();
            if (StringUtils.isNotEmpty(dto.getInvoiceNumber())) {
                wrapper.lambda().eq(InvoiceInfo::getInvoiceNumber, dto.getInvoiceNumber().trim());
            }
            if (dto.getTypes() != null) {
                wrapper.lambda().eq(InvoiceInfo::getReimbursementType, dto.getTypes());
            }
            if (dto.getInvoiceType() != null) {
                wrapper.lambda().eq(InvoiceInfo::getInvoiceType, dto.getInvoiceType());
            }
            if (StringUtils.isNotEmpty(dto.getCreateBy())) {
                wrapper.lambda().like(InvoiceInfo::getCreateBy, dto.getCreateBy());
            }
            if (dto.getTime() != null && dto.getTime().size() > 0) {
                wrapper.lambda().between(InvoiceInfo::getCreationTime,
                        dto.getTime().get(0) + " 00:00:00",
                        dto.getTime().get(1) + " 23:59:59");
            }

            if (userInfo.getRoles() == null) {
                wrapper.lambda().eq(InvoiceInfo::getCreateBy, userInfo.getNameId());
            } else  if (userInfo.getRoles() != null && userInfo.getRoles().equals("admin")) {
                if(cityId == null || cityId.size() == 0){
                    wrapper.lambda().in(InvoiceInfo::getCityId, userInfo.getCityId());
                }else{
                    if(dto.getCityId()!=null){
                        wrapper.lambda().in(InvoiceInfo::getCityId, dto.getCityId());
                    }else{
                        wrapper.lambda().in(InvoiceInfo::getCityId, cityId);
                    }
                }
            } else  if (userInfo.getRoles() != null && userInfo.getRoles().equals("admins")) {
                if(cityId == null || cityId.size() == 0){
                    wrapper.lambda().in(InvoiceInfo::getCityId, userInfo.getCityId());
                }else{
                    if(dto.getCityId()!=null){
                        wrapper.lambda().in(InvoiceInfo::getCityId, dto.getCityId());
                    }else{
                        wrapper.lambda().in(InvoiceInfo::getCityId, cityId);
                    }
                }
            }
            else  if (userInfo.getRoles() != null && userInfo.getRoles().equals("finance")) {
                if(cityId == null || cityId.size() == 0){
                    wrapper.lambda().in(InvoiceInfo::getCityId, userInfo.getCityId());
                }else{
                    if(dto.getCityId()!=null){
                        wrapper.lambda().in(InvoiceInfo::getCityId, dto.getCityId());
                    }else{
                        wrapper.lambda().in(InvoiceInfo::getCityId, cityId);
                    }
                }
            }  else  if (userInfo.getRoles() != null && userInfo.getRoles().equals("vadmin")) {

            }else {
                wrapper.lambda().eq(InvoiceInfo::getCreateBy, userInfo.getNameId());
            }

            if(dto.getCityId()!=null){
                wrapper.lambda().in(InvoiceInfo::getCityId, dto.getCityId());
            }
            
            wrapper.ne("Invoice_status", 4);
            wrapper.orderByDesc("id");
            List<InvoiceInfo> list = this.baseMapper.selectList(wrapper);
            PageInfo<InvoiceInfo> pageInfo = new PageInfo<>(list);
            pageInfo.setList(list);
            return pageInfo;
        } catch (Exception e) {
            throw new AntException(ResultCode.BODY_NOT_MATCH.getCode(), e.getMessage());
        }
    }

    public List<Integer> cityBatchIds(Integer userId) {
        List<UserCity> user_id = userCityMapper.selectList(new QueryWrapper<UserCity>()
                .eq("user_id", userId));
        if(user_id == null || user_id.size() == 0){
            return null;
        }
        return user_id.stream().map(UserCity::getCityId).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultVo InvoiceInfoSave(InvoiceInfo dto) {
        synchronized (this) {
            try {
               UserInfo userInfo = (UserInfo) servletContext.getAttribute("userInfo");
                if (userInfo.getWeChat() == null) {
                    return ResultVo.fail("请绑定个人企业微信");
                }
               // UserInfo userInfo =userInfoService.getOne(new QueryWrapper<UserInfo>().eq("name_id", "1340"));
                dto.setWeChat(userInfo.getWeChat());
                dto.setUserName(userInfo.getUserName());
                if (dto.getInvoiceType() == null) {
                    return ResultVo.fail("请选择类型");
                }
                if (userInfo.getCityId() == null || userInfo.getDepId() == null) {
                    return ResultVo.fail("请绑定个人信息");
                }
                dto.setInvoiceNumber("QK" + RandomUtil.getOrderNumbers(this.baseMapper.selectLastID
                        ()));
                dto.setCityId(userInfo.getCityId());
                dto.setDepId(dto.getDepId() == null ? userInfo.getDepId() : dto.getDepId());
                dto.setAccountUrgency(dto.getAccountUrgency() == null ? "24小时完成" : dto
                        .getAccountUrgency());
                dto.setCreateBy(userInfo.getNameId().toString());
                dto.setCreationTime(new Date());
                if (dto.getInvoiceType() == 2 && dto.getParentId() != null) {
                    InvoiceInfo infos = new InvoiceInfo();
                    infos.setId(dto.getId());
                    infos.setIsReimburse(1);
                    this.baseMapper.updateById(infos);
                    List<ReimburseDetail> detailList = detailService.list(new QueryWrapper<ReimburseDetail>().eq(
                            "parent_id", dto.getId()));
                    dto.setDetailList(detailList);
                }
                if (dto.getInvoiceType() == 2 && dto.getId()==null) {
                    dto.setIsReimburse(1);
                    dto.setAuditStatus(1);
                }
                this.baseMapper.insert(dto);
                //添加详情
                if (dto.getDetailList() != null && dto.getDetailList().size() > 0) {
                    dto.getDetailList().stream().forEach(item -> {
                        item.setParentId(dto.getId());
                        if (item.getProjectAmount() == null || item.getProjectAmount().equals("")) {
                            item.setProjectAmount("1");
                        }
                        detailService.save(item);
                    });
                }

                if (dto.getIsApproved() == 1) {
                    // 判断是否为空
                    AuditList auditList = new AuditList();
                    auditList.setParentId(dto.getId());
                    auditList.setProcessType(dto.getInvoiceType() == 1 ? "funds" : "rent_review");
                    auditList.setCreationTime(new Date());
                    auditList.setName(userInfo.getNameId().toString());

                    if (dto.getApproval().size() == 0 || dto.getApproval() == null) {
                        throw new AntException("请选择审批人员");
                    }
                    // 添加审核记录
                    for (String str : dto.getApproval()) {
                        auditList.setNameId(str);
                        auditList.setTypes("1");
                        auditListService.save(auditList);
                    }
                    if (dto.getNotify().size() == 0 || dto.getNotify() == null) {
                        throw new AntException("请选择抄送人");
                    }
                    for (String str2 : dto.getNotify()) {
                        auditList.setNameId(str2);
                        auditList.setTypes("2");
                        auditListService.save(auditList);
                    }
                    String str = WeChatUtils.launchWeChatData(dto);
                    infoService.update(new UpdateWrapper<InvoiceInfo>().set(
                            "process_instance_id", str)
                            .eq("id", dto.getId()));
                    ApprovalMsg msg = new ApprovalMsg();
                    msg.setParentId(dto.getId());
                    msg.setApprovalType(dto.getInvoiceType() == 1 ? "funds" : "rent_review");
                    msg.setApprovalUser(userInfo.getUserName());
                    msg.setApprovalUserId(userInfo.getNameId());
                    msg.setSpNo(str);
                    msg.setCreationTime(new Date());
                    approvalMsgService.save(msg);
                    return ResultVo.success("操作成功");
                }
                return ResultVo.success("操作成功");

            } catch (Exception e) {
                throw new AntException(ResultCode.FAILURE.getResultCode(), e.getMessage());
            }
        }
    }


    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    public String addWeChatData(InvoiceInfo dto) throws AntException {
        InvoiceInfo info = new InvoiceInfo();
        UserInfo userInfo = (UserInfo) servletContext.getAttribute("userInfo");
        info.setWeChat(userInfo.getWeChat());
        info.setUserName(userInfo.getUserName());
        info.setInvoiceName("物资领料申请");
        info.setReimbursementTypeText("物资领料申请");
        info.setApproval(dto.getApproval());
        info.setNotify(dto.getNotify());
        info.setInvoicePrice(new BigDecimal("0"));
        info.setStartTime(dto.getStartTime());
        info.setEndTime(dto.getEndTime());
        info.setInvoiceNotes(dto.getInvoiceNotes());
        info.setAccountName(null);
        info.setAccountNumber(null);
        info.setAccountBank(null);
        List<ReimburseDetail> list = new ArrayList<>();
        if (dto.getDetailList() != null && dto.getDetailList().size() > 0) {
            dto.getDetailList().forEach(item -> {
                ReimburseDetail detail = new ReimburseDetail();
                detail.setProjectName(item.getProjectName());
                detail.setProjectAmount(item.getProjectAmount());
                detail.setProjectUnit(item.getProjectUnit());
                detail.setProjectPrice(item.getProjectPrice());
                list.add(detail);
            });
        }
        info.setDetailList(list);
        String str = WeChatUtils.launchWeChatData(info);
        return str;
    }


    public List<String> getPicture(String str) throws ApiException {
        if (StringUtils.isEmpty(str)) {
            return null;
        }
        List<Integer> list = Arrays.asList(str.split(",")).
                stream().map(s -> Integer.parseInt(s.trim())).collect(Collectors.toList());
        List<PurchaserRecordImg> imgList = imgService.list(new QueryWrapper<PurchaserRecordImg>()
                .in("id", list));
        List<String> collect = new ArrayList<>();
        if (imgList.size() <= 5) {
            imgList.stream().forEach(item -> {
                collect.add(item.getUrl());
            });
        } else {
            imgList.subList(0, 5).stream().forEach(item -> {
                collect.add(item.getUrl());
            });
        }
        return collect;
    }


    @Override
    public InvoiceInfo InvoiceInfoById(Integer id) {
        InvoiceInfo info = this.baseMapper.selectOne(new QueryWrapper<InvoiceInfo>().eq("id", id));
        if (info == null) {
            throw new AntException(ResultCode.NOT_FOUND);
        }
        List<AuditList> auditList = auditListService.list(new QueryWrapper<AuditList>()
                .eq("parent_id", info.getId())
                .eq("process_type", info.getInvoiceType() == 1 ? "funds" : "rent_review")
                .orderByAsc("id"));
        if (auditList != null) {
            info.setAuditList(auditList);
        }
        ApprovalMsg approvalMsg = approvalMsgService.getOne(new QueryWrapper<ApprovalMsg>().eq("parent_id"
                , id).eq("approval_type", info.getInvoiceType() == 1 ? "funds" : "rent_review"));
        if (approvalMsg != null) {
            info.setApprovalMsgList(approvalMsg);
        }
        if (info.getReimbursementType() != null) {
            CapitalAccount ac = capitalAccountMapper.selectOne(new QueryWrapper<CapitalAccount>()
                    .eq("id", info.getReimbursementType()));
            if (ac != null) {
                info.setReimbursementTypeText(ac.getAccountName());
            }
        }
        if (info.getAnnex() != null && StringUtils.isNotEmpty(info.getAnnex())) {
            List<PurchaserRecordImg> imgList = imgService.list(new QueryWrapper<PurchaserRecordImg>().in("id",
                    Arrays.asList(info.getAnnex().split(","))));
            info.setAnnexList(imgList);
        }
        List<ReimburseDetail> detail = detailService.list(new QueryWrapper<ReimburseDetail>()
                .eq("parent_id", info.getId()));
        if (detail != null) {
            info.setDetailList(detail);
        }
        return info;
    }

    @Override
    public AuditList selectIsAudit(String processInstanceId, String user_id) {
        InvoiceInfo invoiceInfo = infoService.getOne(new QueryWrapper<InvoiceInfo>()
                .eq("process_instance_id", processInstanceId));
        if (invoiceInfo != null) {
            AuditList parentId = auditListService.getOne(new QueryWrapper<AuditList>()
                    .eq("parent_id", invoiceInfo.getId())
                    .eq("process_type", "funds")
                    .eq("types", "1")
                    .eq("name_id", user_id));
            if (parentId != null) {
                return parentId;
            }
            return null;
        }
        return null;
    }

    @Override
    public void getprocessInstanceIdById(String processInstanceId, String opinion) {
        InvoiceInfo procurement = infoService.getOne(new QueryWrapper<InvoiceInfo>().eq("process_instance_id",
                processInstanceId));
        if (procurement != null) {
            infoService.update(new UpdateWrapper<InvoiceInfo>()
                    .set("audit_status", opinion.equals("agree") ? 1 : 2)
                    .eq("process_instance_id", processInstanceId));
        }
        HouseLease lease = leaseService.getOne(new QueryWrapper<HouseLease>().eq("process_instance_id",
                processInstanceId));
        if (lease != null) {
            leaseService.update(new UpdateWrapper<HouseLease>()
                    .set("examine", opinion.equals("agree") ? 1 : 2)
                    .eq("process_instance_id", processInstanceId));
        }

        if (procurement.getReimbursementType() == 28) {
            BidInformation information = bidInformationService.getOne(new QueryWrapper<BidInformation>().eq("id",
                    procurement.getHouseLeaseId()));
            if (information != null) {
                List<ReimburseDetail> details = detailService.list(new QueryWrapper<ReimburseDetail>().eq(
                        "parent_id", procurement.getId()));
                bidInformationService.updateTendering(details, procurement.getHouseLeaseId());
            }
        }

    }

    @Override
    public AuditList selectIsAudits(String processInstanceId, String user_id) {
        InvoiceInfo invoiceInfo = infoService.getOne(new QueryWrapper<InvoiceInfo>()
                .eq("process_instance_id", processInstanceId));
        if (invoiceInfo != null) {
            AuditList parentId = auditListService.getOne(new QueryWrapper<AuditList>()
                    .eq("parent_id", invoiceInfo.getId())
                    .eq("process_type", "rent_review")
                    .eq("types", "1")
                    .eq("name_id", user_id));
            if (parentId != null) {
                return parentId;
            }
            return null;
        }
        return null;
    }

    @Override
    public void getprocessInstanceIdByIds(String processInstanceId, String opinion) {
        InvoiceInfo procurement = infoService.getOne(new QueryWrapper<InvoiceInfo>().eq("process_instance_id",
                processInstanceId));
        if (procurement != null) {
            infoService.update(new UpdateWrapper<InvoiceInfo>()
                    .set("audit_status", opinion.equals("agree") ? 1 : 2)
                    .eq("process_instance_id", processInstanceId));
        }
    }

    @Override
    public ResultVo RsendDingTalk(Integer id) throws Exception {
        UserInfo userInfo = (UserInfo) servletContext.getAttribute("userInfo");
        InvoiceInfo info = infoService.getOne(new QueryWrapper<InvoiceInfo>().eq("id", id));
        if (info == null) {
            throw new AntException("申请记录不存在");
        }
        info.setWeChat(userInfo.getWeChat());
        if (userInfo.getCityId() == null && userInfo.getDepId() == null) {
            throw new AntException(ResultCode.FAILURE.getResultCode(), "请绑定个人信息");
        }
        List<AuditList> list = auditListService.list(new QueryWrapper<AuditList>()
                .eq("process_type", info.getInvoiceType() == 1 ? "funds" : "rent_review").eq("parent_id", id));
        if (list == null) {
            throw new AntException("审核记录不存在");
        }
        List<String> approver = new ArrayList<>();
        List<String> cc = new ArrayList<>();
        if (list != null && list.size() > 0) {
            list.stream().forEach(item -> {
                if (item.getTypes().equals("1")) {
                    approver.add(item.getNameId());
                } else {
                    cc.add(item.getNameId());
                }
            });
        }

        if (info == null) {
            throw new AntException("申请记录不存在");
        }
        info.setApproval(approver);
        info.setNotify(cc);
        info.setUserName(userInfo.getUserName());

        List<ReimburseDetail> detailList = detailService.list(new QueryWrapper<ReimburseDetail>()
                .eq("parent_id", id));
        detailList.removeAll(Collections.singleton(null));
        if (detailList != null && detailList.size() > 0) {
            info.setDetailList(detailList);
        } else {
            ReimburseDetail detail = new ReimburseDetail();
            detail.setProjectName("房屋租赁合同");
            detail.setProjectUnit("间");
            detail.setProjectPrice(info.getInvoicePrice());
            detailList.add(detail);
            info.setDetailList(detailList);
        }
        String str = WeChatUtils.launchWeChatData(info);
        infoService.update(new UpdateWrapper<InvoiceInfo>().set(
                "process_instance_id", str)
                .eq("id", id));

        ApprovalMsg msg = new ApprovalMsg();
        msg.setParentId(info.getId());
        msg.setApprovalType(info.getInvoiceType() == 1 ? "funds" : "rent_review");
        msg.setApprovalUser(info.getUserName());
        msg.setApprovalUserId(Integer.parseInt(info.getCreateBy()));
        msg.setSpNo(str);
        msg.setCreationTime(new Date());
        approvalMsgService.save(msg);
        return ResultVo.success("提交失败");

    }

    @Override
    public ResultVo RsendDingTalks(Integer id, Integer uid) throws Exception {
        UserInfo userInfo = userInfoService.getOne(new QueryWrapper<UserInfo>().eq("name_id", uid));
        InvoiceInfo info = infoService.getOne(new QueryWrapper<InvoiceInfo>().eq("id", id));
        info.setWeChat(userInfo.getWeChat());
        if (info == null) {
            throw new AntException("申请记录不存在");
        }
        List<AuditList> list = auditListService.list(new QueryWrapper<AuditList>()
                .eq("process_type", info.getInvoiceType() == 1 ? "funds" : "rent_review").eq("parent_id", id));
        if (list == null) {
            throw new AntException("审核记录不存在");
        }
        List<String> approver = new ArrayList<>();
        List<String> cc = new ArrayList<>();
        if (list != null && list.size() > 0) {
            list.stream().forEach(item -> {
                if (item.getTypes().equals("1")) {
                    approver.add(item.getNameId());
                } else {
                    cc.add(item.getNameId());
                }
            });
        }

        info.setApproval(approver);
        info.setNotify(cc);
        info.setUserName(userInfo.getUserName());
        info.setReimbursementTypeText(getReimbursementTypeText(info.getReimbursementType()));

        List<PurchaserRecordImg> imgList = imgService.list(new QueryWrapper<PurchaserRecordImg>().in("id",
                Arrays.asList(info.getAnnex().split(","))));

       // info.setAnnexs(imgList.stream().map(item -> item.getUrl()).collect(Collectors.toList()));
        info.setMediaId(imgList.stream().map(item -> item.getMediaId()).collect(Collectors.toList()));

        List<ReimburseDetail> detailList = detailService.list(new QueryWrapper<ReimburseDetail>()
                .eq("parent_id", id));
        detailList.removeAll(Collections.singleton(null));
        if (detailList != null && detailList.size() > 0) {
            info.setDetailList(detailList);
        }
        else {
            ReimburseDetail detail = new ReimburseDetail();
            detail.setProjectName("房屋租房费用");
            detail.setProjectUnit("间");
            detail.setProjectPrice(info.getInvoicePrice());
            detailList.add(detail);
            info.setDetailList(detailList);
        }
        String str = WeChatUtils.launchWeChatData(info);
        infoService.update(new UpdateWrapper<InvoiceInfo>().set(
                "process_instance_id", str)
                .eq("id", id));

        ApprovalMsg msg = new ApprovalMsg();
        msg.setParentId(info.getId());
        msg.setApprovalType(info.getInvoiceType() == 1 ? "funds" : "rent_review");
        msg.setApprovalUser(info.getUserName());
        msg.setApprovalUserId(Integer.parseInt(info.getCreateBy()));
        msg.setSpNo(str);
        msg.setCreationTime(new Date());
        approvalMsgService.save(msg);
        return ResultVo.success("提交失败");
    }

    /**
     * 获取历史审批记录
     *
     * @param tid
     * @return
     */
    @Override
    public List<AuditList> getHistoryDingTalk(Integer tid) {
        List<AuditList> list;
        UserInfo userInfo = (UserInfo) servletContext.getAttribute("userInfo");
        InvoiceInfo info = infoService.getOne(new QueryWrapper<InvoiceInfo>().
                eq("id", userInfo.getNameId()).last("order by id  DESC limit 1")
        );
        if (info != null) {
            if (tid == 1) {
                list = auditListService.list(new QueryWrapper<AuditList>().eq("process_type", "funds")
                        .eq("parent_id", info.getId()));
            } else {
                list = auditListService.list(new QueryWrapper<AuditList>().eq("process_type", "rent_review")
                        .eq("parent_id", info.getId()));
            }
            return list;
        }
        return null;
    }

    @Override
    public ResultVo syncDingTalks(Integer id) {
        InvoiceInfo info = this.baseMapper.selectOne(new QueryWrapper<InvoiceInfo>().eq("id", id));
        if (info != null) {
            infoService.update(new UpdateWrapper<InvoiceInfo>().set("audit_status", 1).eq("id", id));
            auditListService.update(new UpdateWrapper<AuditList>()
                    .set("status", 2).eq("types", 1)
                    .eq("process_type", "rent_review")
                    .eq("parent_id", id));
            return ResultVo.success("操作成功");
        }
        return ResultVo.fail("操作失败");
    }


    private String getReimbursementTypeText(Integer typeId) {
        CapitalAccount account = accountService.getOne(new QueryWrapper<CapitalAccount>().eq("id",typeId));
        return account.getAccountName();
    }
}
